package com.thinking.live.controller;

import com.alipay.api.AlipayConstants;
import com.alipay.api.internal.util.AlipaySignature;
import com.thinking.live.config.AlipayConfig;
import com.thinking.live.entity.pojo.req.RechargeResultReq;
import com.thinking.live.event.OrderPayResultDTOEvent;
import com.thinking.live.event.RechargeResultReqEvent;
import com.thinking.live.vo.dto.OrderPayResultDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

@RestController
@RequestMapping("/openapi/result")
@Slf4j
public class RechargeResultController {


    @Autowired
    private ApplicationEventPublisher   publisher;
//    /**
//     * 充值结果通知
//     * @param request
//     * @return
//     */
//    @RequestMapping(value = "/reslutInform",method = {RequestMethod.GET,RequestMethod.POST})
//    public String  reslutInform(RechargeResultReq request) {
//        log.info("return-living-data-1:{}",request);
//        publisher.publishEvent(new RechargeResultReqEvent(request));
//        return "success";
//    }
    private final ReentrantLock lock = new ReentrantLock();

    @Resource
    private AlipayConfig alipayConfig;
    /**
     * 服务器异步通知页面路径，接收支付宝回调后，再封装页面数据，直接返回相应页面到前端
     * 支付、退款都会通过此回调接口
     *
     * @param request
     * @param response
      * @deprecated API地址：https://opendocs.alipay.com/open/203/105286
     */
    @PostMapping("/openapi/notify")
    public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.info("异步通知");
        PrintWriter out = response.getWriter();
        if (lock.tryLock()) {
            try {
                //乱码解决，这段代码在出现乱码时使用
                request.setCharacterEncoding("utf-8");
                //获取支付宝POST过来反馈信息
                Map<String, String> params = new HashMap<>(8);
                Map<String, String[]> requestParams = request.getParameterMap();
                for (Map.Entry<String, String[]> stringEntry : requestParams.entrySet()) {
                    String[] values = stringEntry.getValue();
                    String valueStr = "";
                    for (int i = 0; i < values.length; i++) {
                        valueStr = (i == values.length - 1) ? valueStr + values[i]
                                : valueStr + values[i] + ",";
                    }
                    params.put(stringEntry.getKey(), valueStr);
                }

                //调用SDK验证签名
                boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getPublicKey(), AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2);

                if (!signVerified) {
                    log.error("验签失败");
                    out.print("fail");
                    return;
                }

                log.warn("=========== 在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱 ===========");

                // 通知ID
                String notifyId = new String(params.get("notify_id").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                // 通知时间
                String notifyTime = new String(params.get("notify_time").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                //商户订单号,之前生成的带用户ID的订单号
                String outTradeNo = new String(params.get("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                //支付宝交易号
                String tradeNo = new String(params.get("trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                //付款金额
                String totalAmount = new String(params.get("total_amount").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                //交易状态
                String tradeStatus = new String(params.get("trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

                /*
                 * 交易状态
                 * TRADE_SUCCESS 交易完成
                 * TRADE_FINISHED 支付成功
                 * WAIT_BUYER_PAY 交易创建
                 * TRADE_CLOSED 交易关闭
                 */
                log.info("tradeStatus:" + tradeStatus);

                if ("TRADE_FINISHED".equals(tradeStatus)) {
                    /*此处可自由发挥*/
                    //判断该笔订单是否在商户网站中已经做过处理
                    //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                    //如果有做过处理，不执行商户的业务程序
                    //注意：
                    //退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
                } else if ("TRADE_SUCCESS".equals(tradeStatus)) {
                    // TODO 根据订单号，做幂等处理，并且在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱
                    log.warn("=========== 根据订单号，做幂等处理 ===========");

                    //判断该笔订单是否在商户网站中已经做过处理
                    //如果没有做过处理，根据订单号（out_trade_no在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                    //如果有做过处理，不执行商户的业务程序

                    // 此处代表交易已经成果，编写实际页面代码
                    // 比如：重置成功，那么往数据库中写入重置金额
                    log.info("notifyId:" + notifyId);
                    log.info("notifyTime:" + notifyTime);
                    log.info("trade_no:" + tradeNo);
                    log.info("outTradeNo:" + outTradeNo);
                    log.info("totalAmount:" + totalAmount);
                    OrderPayResultDTO orderPayResultDTO=new OrderPayResultDTO();
                    orderPayResultDTO.setOrderNo(outTradeNo);
                    orderPayResultDTO.setOutPayOrderNo(tradeNo);
                    orderPayResultDTO.setPayAmount(Integer.parseInt(totalAmount));
                    publisher.publishEvent(new OrderPayResultDTOEvent(orderPayResultDTO));

                }
            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }
        out.print("success");

    }

}
